package top.lshaci.learning.netty.simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;

/**
 * NettyServerHandler
 * <pre>
 *     1. 自定义 Handler
 *
 * </pre>
 *
 * @author lshaci
 * @since 1.0.0
 */
@Slf4j
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    /**
     * 读取数据事件（这里可以读取客户端发送的消息）
     *
     * @param ctx 含有 pipeline, channel, address
     * @param msg 客户端发送的数据
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        log.debug("Server context: {}", ctx);
        // 将 msg 转成 ByteBuf
        ByteBuf byteBuf = (ByteBuf) msg;

        log.debug("客户端: {} => {}", ctx.channel().remoteAddress(), byteBuf.toString(CharsetUtil.UTF_8));
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, 客户端, Read!", CharsetUtil.UTF_8));
        // 将用户自定义任务加入到 taskQueue
        ctx.channel().eventLoop().execute(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
                ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, 客户端, Task Queue!", CharsetUtil.UTF_8));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        // 将用户自定义定时任务加入到 scheduleTaskQueue
        ctx.channel().eventLoop().schedule(() -> {
            ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, 客户端, Schedule Task Queue!", CharsetUtil.UTF_8));
        }, 5, TimeUnit.SECONDS);
    }

    /**
     * 数据读取完毕后执行
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        // 将输入写入缓存, 并刷入到
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, 客户端, Read Complete!", CharsetUtil.UTF_8));
    }

    /**
     * 处理异常，一般是要关闭通道
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}
